﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2025   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTools
 * 唯一标识：1ef392ce-4fbc-4c68-bb2f-a9416cc2aceb
 * 文件名：LineTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guoweihao-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2025/5/23 16:28:20
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -


namespace AutoCAD.EntityTools
{
    /// <summary>
    /// LineTools 的摘要说明
    /// </summary>
    public static class LineTools
    {


        /// <summary>
        /// 获取直线长
        /// </summary>
        /// <returns></returns>
        public static double GetLineLength(this Line line)
        {
            if (line == null) return 0;
            var start = line.StartPoint;
            var end = line.EndPoint;
            return start.DistanceTo(end);
        }


        /// <summary>
        /// 手选直段线
        /// </summary>
        /// <param name="ed">Editor</param>
        /// <param name="prompt">提示信息</param>
        /// <returns></returns>
        public static Line SelectLine(this Editor ed, string prompt = "\n请选择直线: ")
        {
            if (ed == null) return new Line();
            PromptEntityOptions options = new PromptEntityOptions(prompt);
            var line = new Line();
            options.SetRejectMessage(prompt);
            options.AddAllowedClass(typeof(Line), true);
            PromptEntityResult result = ed.GetEntity(options);
            if (result.Status == PromptStatus.OK)
            {
                $"{result.ObjectId}".CadMessage2();
                line = ed.GetEntity<Line>(result.ObjectId);
                return line;
            }
            else
                $"选择取消".CadMessage2();
            return line;
        }

        /// <summary>
        /// 计算两条平行线之间的最短距离
        /// </summary>
        /// <param name="line1"></param>
        /// <param name="line2"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public static double CalculateShortestDistanceBetweenParallelLines(this Line line1, Line line2, double tolerance)
        {
            // 检查输入是否有效
            if (line1 == null || line2 == null)
                return double.NaN;
            var tolerance_cad = new Autodesk.AutoCAD.Geometry.Tolerance(tolerance, tolerance);
            // 获取两条直线的方向向量
            Vector3d dir1 = line1.EndPoint - line1.StartPoint;
            Vector3d dir2 = line2.EndPoint - line2.StartPoint;

            // 检查两条直线是否平行
            if (!dir1.IsParallelTo(dir2, tolerance_cad))
                return double.NaN;

            // 归一化方向向量
            dir1 = dir1.GetNormal();
            dir2 = dir2.GetNormal();

            // 计算两条直线间的垂直距离
            // 方法：计算line1上任意一点到line2的距离
            Point3d pointOnLine1 = line1.StartPoint;

            // 计算line2上距离pointOnLine1最近的点
            Point3d closestPointOnLine2 = GetClosestPointOnLine(pointOnLine1, line2);

            // 计算两点之间的距离
            double distance = pointOnLine1.DistanceTo(closestPointOnLine2);

            // 为了确保得到的是最短距离，再检查line2的点到line1的距离
            Point3d pointOnLine2 = line2.StartPoint;
            Point3d closestPointOnLine1 = GetClosestPointOnLine(pointOnLine2, line1);
            double reverseDistance = pointOnLine2.DistanceTo(closestPointOnLine1);

            // 返回较小的距离（理论上应该相同，但处理浮点误差）
            return Math.Min(distance, reverseDistance);
        }
        /// <summary>
        /// 获取直线上距离给定点最近的点
        /// </summary>
        private static Point3d GetClosestPointOnLine(Point3d point, Line line)
        {
            Vector3d lineVec = line.EndPoint - line.StartPoint;
            Vector3d pointVec = point - line.StartPoint;

            double t = pointVec.DotProduct(lineVec) / lineVec.DotProduct(lineVec);

            // 限制t在[0,1]范围内，确保点在直线段上
            t = Math.Max(0, Math.Min(1, t));

            return line.StartPoint + lineVec * t;
        }







        #region 优化截取逻辑
        /// <summary>
        /// 检查直线相交并在相交处裁剪两条线的短边（仅当短边有长度时）
        /// </summary>
        public static void TrimValidShortSidesAtIntersections(this Document doc, List<ObjectId> lineIds)
        {
            if (lineIds == null || lineIds.Count < 2)
                return;

            Database db = doc.Database;
            Editor ed = doc.Editor;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                    // 获取所有直线对象
                    var lines = lineIds.Select(id => tr.GetObject(id, OpenMode.ForWrite) as Line).ToList();

                    // 找出所有相交的直线对
                    var intersectingPairs = FindIntersectingLinePairs(lines);

                    int trimCount = 0;

                    // 处理每对相交直线
                    foreach (var pair in intersectingPairs)
                    {
                        if (TrimBothLinesAtIntersection(pair.Item1, pair.Item2))
                        {
                            trimCount++;
                        }
                    }

                    tr.Commit();
                    ed.WriteMessage($"\n处理完成，共裁剪 {trimCount} 处相交点");
                }
                catch (System.Exception ex)
                {
                    ed.WriteMessage($"\n错误: {ex.Message}");
                    tr.Abort();
                }
            }
        }
        /// <summary>
        /// 检查并裁剪线段短边
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        private static List<Tuple<Line, Line>> FindIntersectingLinePairs(List<Line> lines)
        {
            List<Tuple<Line, Line>> intersectingPairs = new List<Tuple<Line, Line>>();

            for (int i = 0; i < lines.Count; i++)
            {
                for (int j = i + 1; j < lines.Count; j++)
                {
                    Line line1 = lines[i];
                    Line line2 = lines[j];

                    Point3dCollection intersectionPoints = new Point3dCollection();
                    if (line1 != null && line2 != null)
                    {
                        line1.IntersectWith(line2, Intersect.OnBothOperands, intersectionPoints, IntPtr.Zero, IntPtr.Zero);

                        if (intersectionPoints.Count > 0 &&
                            !IsIntersectionAtEndpoint(line1, intersectionPoints[0]) &&
                            !IsIntersectionAtEndpoint(line2, intersectionPoints[0]))
                        {
                            intersectingPairs.Add(new Tuple<Line, Line>(line1, line2));
                        }
                    }
                }
            }

            return intersectingPairs;
        }
        /// <summary>
        /// 判断交点是否在直线的端点
        /// </summary>
        /// <param name="line"></param>
        /// <param name="intersection"></param>
        /// <returns></returns>
        private static bool IsIntersectionAtEndpoint(Line line, Point3d intersection)
        {
            const double tolerance = 1e-6;
            return line.StartPoint.DistanceTo(intersection) < tolerance ||
                   line.EndPoint.DistanceTo(intersection) < tolerance;
        }
        /// <summary>
        /// 检查并裁剪线段短边
        /// </summary>
        /// <param name="line1"></param>
        /// <param name="line2"></param>
        /// <returns></returns>
        private static bool TrimBothLinesAtIntersection(Line line1, Line line2)
        {
            Point3dCollection intersectionPoints = new Point3dCollection();
            line1.IntersectWith(line2, Intersect.OnBothOperands, intersectionPoints, IntPtr.Zero, IntPtr.Zero);
            if (intersectionPoints.Count == 0) return false;

            Point3d intersection = intersectionPoints[0];
            bool trimmed1 = TrimLineShortSideIfValid(line1, intersection);
            bool trimmed2 = TrimLineShortSideIfValid(line2, intersection);

            return trimmed1 || trimmed2;
        }

        /// <summary>
        /// 裁剪直线的短边部分（仅当短边有长度时）
        /// </summary>
        /// <param name="line">要裁剪的直线</param>
        /// <param name="intersection">交点</param>
        /// <returns>是否执行了裁剪操作</returns>
        private static bool TrimLineShortSideIfValid(Line line, Point3d intersection)
        {
            const double minLength = 1e-6; // 最小有效长度阈值

            double startDist = line.StartPoint.DistanceTo(intersection);
            double endDist = line.EndPoint.DistanceTo(intersection);

            if (startDist < endDist)
            {
                if (startDist > minLength) // 只有当短边有足够长度时才裁剪
                {
                    line.StartPoint = intersection;
                    return true;
                }
            }
            else
            {
                if (endDist > minLength) // 只有当短边有足够长度时才裁剪
                {
                    line.EndPoint = intersection;
                    return true;
                }
            }

            return false;
        }

        #endregion



        #region 生成中线

        /// <summary>
        /// 计算两条平行曲线之间的中线（支持不等长情况）
        /// </summary>
        /// <param name="curve1">第一条曲线</param>
        /// <param name="curve2">第二条曲线</param>
        /// <returns>中线列表（可能包含多条线段）</returns>
        public static List<Curve> CalculateCenterLines(this Curve curve1, Curve curve2,
            double distanceTolerance)
        {
            List<Curve> centerLines = new List<Curve>();

            // 检查输入有效性
            if (curve1 == null || curve2 == null)
                return centerLines;

            // 处理直线情况
            if (curve1 is Line line1 && curve2 is Line line2)
            {
                var line = CalculateLineCenterLine(line1, line2, distanceTolerance);
                if (line != null)
                    centerLines.Add(line);
            }
            // 处理圆弧情况z
            else if (curve1 is Arc arc1 && curve2 is Arc arc2)
            {
                centerLines.Add(CalculateArcCenterLine(arc1, arc2));
            }
            //处理多段线情况
            else if (curve1 is Polyline pl1 && curve2 is Polyline pl2)
            {
                var plcenter = pl1.CreateCenterLineByExploding(pl2, distanceTolerance);

                //if (plcenter != null)
                centerLines.AddRange(plcenter);
            }
            // 可以添加对其他曲线类型的支持

            return centerLines;
        }



        /// <summary>
        /// 计算两条平行圆弧的中线
        /// </summary>
        private static Arc CalculateArcCenterLine(Arc arc1, Arc arc2)
        {
            // 检查法向量方向
            Vector3d normal1 = arc1.Normal;
            Vector3d normal2 = arc2.Normal;

            if (normal1.DotProduct(normal2) < 0)
                normal2 = -normal2;

            // 计算中点参数
            Point3d center = (arc1.Center.Add(arc2.Center)) / 2;
            double radius = (arc1.Radius + arc2.Radius) / 2;

            // 计算角度范围（取两者的并集）
            double startAngle = Math.Min(arc1.StartAngle, arc2.StartAngle);
            double endAngle = Math.Max(arc1.EndAngle, arc2.EndAngle);




            // 确保角度有效
            if (startAngle > endAngle)
            {
                double temp = startAngle;
                startAngle = endAngle;
                endAngle = temp;
            }
            //采用原有的弧度
            startAngle = arc1.StartAngle;
            endAngle = arc1.EndAngle;
            return new Arc(center, normal1, radius, startAngle, endAngle);
        }



        ///// <summary>
        ///// 计算两条平行直线的中线（优化版）
        ///// </summary>
        //public static Line CalculateLineCenterLine(Line line1, Line line2, double distanceTolerance)
        //{
        //    //测试
        //    //return line1.GetCenterLine(line2);

        //    //const double tolerance = 1e-5; // 几何计算容差
        //    Point3d midStart = new Point3d();
        //    Point3d midEnd = new Point3d();
        //    // 1. 验证输入有效性
        //    if (line1 == null || line2 == null)
        //        throw new ArgumentNullException("输入直线不能为null");

        //    var thickness = line1.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
        //    var addThickness = thickness / 2;

        //    //var allowThickness = ConfigPath.GetCustomConfig().AllowedDistances;

        //    //var contains = allowThickness.ContainsThickness(addThickness, tolerance);
        //    //if (!contains)
        //    //    return null;


        //    // 2. 计算方向向量（带归一化处理）
        //    Vector3d dir1 = (line1.EndPoint - line1.StartPoint).GetNormal();
        //    Vector3d dir2 = (line2.EndPoint - line2.StartPoint).GetNormal();

        //    // 3. 确保方向一致（处理反向平行情况）
        //    if (dir1.DotProduct(dir2) < -0.99) // 近似反平行
        //    {
        //        dir2 = -dir2;
        //    }
        //    else if (Math.Abs(dir1.DotProduct(dir2)) < 0.99) // 非平行线
        //    {
        //        throw new ArgumentException("输入直线必须平行");
        //    }

        //    // 4. 计算投影参数（优化算法）
        //    Point3d[] testPoints = { line1.StartPoint, line1.EndPoint, line2.StartPoint, line2.EndPoint };

        //    double minT = double.MaxValue;
        //    double maxT = double.MinValue;
        //    bool useLine1AsBase = true;

        //    // 选择较长直线作为基准线
        //    double len1 = line1.Length;
        //    double len2 = line2.Length;
        //    Line baseLine = len1 > len2 ? line1 : line2;
        //    Line otherLine = len1 > len2 ? line2 : line1;
        //    Vector3d baseDir = (baseLine.EndPoint - baseLine.StartPoint).GetNormal();

        //    foreach (var point in testPoints)
        //    {
        //        Vector3d vec = point - baseLine.StartPoint;
        //        double t = vec.DotProduct(baseDir);

        //        minT = Math.Min(minT, t);
        //        maxT = Math.Max(maxT, t);
        //    }

        //    // 5. 处理特殊情况（如零长度线段）
        //    if (Math.Abs(maxT - minT) < distanceTolerance)
        //    {
        //        // 取两条直线的中点连线  - 逻辑错误
        //        //Point3d mid1 = (line1.StartPoint.Add(line1.EndPoint)) / 2;
        //        //Point3d mid2 = (line2.StartPoint.Add(line2.EndPoint)) / 2;


        //        //return new Line(mid1, mid2);

        //        midStart = (line1.StartPoint.Add(baseDir * minT).Add(
        //          GetProjectionPoint(line2, line1.StartPoint + baseDir * minT))) / 2;

        //        midEnd = (line1.StartPoint.Add(baseDir * maxT).Add(
        //                        GetProjectionPoint(line2, line1.StartPoint + baseDir * maxT))) / 2;

        //        /*
        //         * 新增距离检查
        //         * 生成墙中线和两根墙线的距离相加
        //         * 减去两根线的距离
        //         * 相减不小于误差值
        //         */
        //        var resLine1 = new Line(midStart, midEnd);
        //        var dis1_i = resLine1.CalculateShortestDistanceBetweenParallelLines(line1, distanceTolerance);
        //        var dis2_i = resLine1.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
        //        if (Math.Abs((dis1_i + dis2_i) - thickness) <= distanceTolerance)
        //        {
        //            return resLine1;
        //        }
        //        else
        //        {
        //            //return null;
        //            return new Line(midStart, midEnd);
        //        }

        //    }
        //    return new Line(midStart, midEnd);

        //}






        /// <summary>
        /// 计算两条平行直线的中线（优化版）
        /// </summary>
        /// <param name="line1">第一条直线</param>
        /// <param name="line2">第二条直线</param>
        /// <param name="distanceTolerance">距离容差</param>
        /// <returns>中线对象，如果输入无效则返回null</returns>
        public static Line CalculateLineCenterLine(Line line1, Line line2, double distanceTolerance)
        {
            // 1. 参数验证
            if (line1 == null || line2 == null)
            {
                throw new ArgumentNullException("输入直线不能为null");
            }

            if (distanceTolerance <= 0)
            {
                throw new ArgumentException("距离容差必须大于0");
            }

            // 2. 计算两线距离并检查平行性
            double thickness;
            try
            {
                thickness = line1.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);
            }
            catch (ArgumentException ex)
            {
                // 如果不平行则返回null
                return null;
            }

            // 3. 获取归一化方向向量
            Vector3d dir1 = (line1.EndPoint - line1.StartPoint).GetNormal();
            Vector3d dir2 = (line2.EndPoint - line2.StartPoint).GetNormal();

            // 4. 确保方向一致
            if (dir1.DotProduct(dir2) < -0.99) // 近似反平行
            {
                dir2 = -dir2;
            }

            // 5. 选择较长直线作为基准线
            bool useLine1AsBase = line1.Length >= line2.Length;
            Line baseLine = useLine1AsBase ? line1 : line2;
            Line otherLine = useLine1AsBase ? line2 : line1;
            Vector3d baseDir = (baseLine.EndPoint - baseLine.StartPoint).GetNormal();

            // 6. 计算投影参数范围
            Point3d[] testPoints = { line1.StartPoint, line1.EndPoint, line2.StartPoint, line2.EndPoint };

            double minT = double.MaxValue;
            double maxT = double.MinValue;

            foreach (var point in testPoints)
            {
                Vector3d vec = point - baseLine.StartPoint;
                double t = vec.DotProduct(baseDir);
                minT = Math.Min(minT, t);
                maxT = Math.Max(maxT, t);
            }

            // 7. 计算中线端点
            Point3d GetMidPoint(double t)
            {
                Point3d basePoint = baseLine.StartPoint + baseDir * t;
                Point3d otherProjection = GetProjectionPoint(otherLine, basePoint);
                return (basePoint.Add(otherProjection)) / 2.0;
            }

            Point3d midStart = GetMidPoint(minT);
            Point3d midEnd = GetMidPoint(maxT);

            // 8. 验证中线距离
            Line centerLine = new Line(midStart, midEnd);
            double dis1 = centerLine.CalculateShortestDistanceBetweenParallelLines(line1, distanceTolerance);
            double dis2 = centerLine.CalculateShortestDistanceBetweenParallelLines(line2, distanceTolerance);

            if (Math.Abs((dis1 + dis2) - thickness) > distanceTolerance)
            {
                return null; // 距离验证失败
            }

            return centerLine;
        }

        ///// <summary>
        ///// 获取点在直线上的投影点
        ///// </summary>
        //private static Point3d GetProjectionPoint(Line line, Point3d point)
        //{
        //    Vector3d lineVec = line.EndPoint - line.StartPoint;
        //    Vector3d pointVec = point - line.StartPoint;
        //    double t = pointVec.DotProduct(lineVec) / lineVec.DotProduct(lineVec);
        //    return line.StartPoint + lineVec * t;
        //}






        /// <summary>
        /// 获取点在直线上的投影点
        /// </summary>
        public static Point3d GetProjectionPoint(Line line, Point3d point)
        {
            Vector3d vec = line.EndPoint - line.StartPoint;
            Vector3d pointVec = point - line.StartPoint;
            double t = pointVec.DotProduct(vec) / vec.LengthSqrd;
            return line.StartPoint + vec * t;
        }

        #endregion
    }
}